--桌子逻辑
local skynet = require "skynet"
local cluster = require "skynet.cluster"
local tabletool = require "tabletool"
local timetool = require "timetool"
local timer = require "timer"
local filelog = require "filelog"
local configdao = require "configdao"
local cardtool = require "mjexcardtool"
local json = require "cjson"
json.encode_sparse_array(true, 1, 1)

require "mjexenum"

local TableLogic = {}
local service = nil
local seatlogic = nil
local gamelogic = nil

function TableLogic.init(caller)
	service = caller
end

-- 在tablecmd:start 调用的
-- 这里的 tableobj，其实就是 table_data
-- conf 是从客户端传上来的, table_conf
--
function TableLogic.init_data(tableobj, conf, attachconf)
	-- 这里的两个logic 是tablelogic后面才加入进去的，所以没办法放到 init() 里面去初始化
	seatlogic = service:get_logicbyname("seatlogic")

	-- 获得游戏逻辑
	gamelogic = service:get_logicbyname("gamelogic")
	if conf == nil  then
		filelog.sys_error("TableLogic.init_data conf == nil", conf)
		return false
	end

    --初始化桌子信息
	local now = timetool.get_time()
    local nodename = skynet.getenv("nodename")
	tableobj.table_type = conf.table_type
	tableobj.uuid = nodename .. "_" .. attachconf.code .. "_" .. attachconf.index .. "_" .. now
	tableobj.index = attachconf.index
	tableobj.code = attachconf.code
	tableobj.state = EMJTableState.TABLE_STATE_WAIT_PLAYER_SITDOWN
	tableobj.create_rid = attachconf.rid
	tableobj.create_rolename = attachconf.rolename
    tableobj.create_logo = attachconf.logo
	tableobj.create_time = now
	tableobj.cur_player_num = 0
	tableobj.curr_to_num = 0
    tableobj.retain_to_num = conf.retain_to_num
	tableobj.conf = conf
    tableobj.intable_player_num = 0
    tableobj.cur_watch_playernum = 0
    tableobj.table_service = attachconf.table_service
    tableobj.disband_timeout_time = 0
    tableobj.sitdown_player_num = 0
    tableobj.agencylevel = attachconf.agencylevel            --代理等级，0表示非代理创建桌
    tableobj.table_persist = attachconf.table_persist        --桌子没人时，保留时间
    tableobj.tradeid = attachconf.tradeid
    tableobj.is_huansanzhang = false
    tableobj.is_dingque = false
    tableobj.last_heart_time = now
    tableobj.is_limit_win_or_lose = true    --输赢上限
    tableobj.is_can_half_leave = true       --是否可以中途离桌
    tableobj.is_roll_dice = false           --是否摇骰子

    --匹配场
    tableobj.is_matchtable = false
    if attachconf.is_matchtable then
        tableobj.is_matchtable = true
        tableobj.match_type = attachconf.match_type or 1
    end

    --设置练习场托管时间
    if tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
        tableobj.do_tuoguan_time = 1
    end

    --设置超时时间
    if not tableobj.conf.action_timeout or tableobj.conf.action_timeout <= 0 then
        tableobj.conf.action_timeout = 20  --测试 20
    end

    --设置底注
    if not tableobj.conf.score_diamond or tableobj.conf.score_diamond < 0 then
        tableobj.conf.score_diamond = 0
    end

    --设置进桌携带量
    if not tableobj.conf.enter_diamond or tableobj.conf.enter_diamond < 0 then
        tableobj.conf.enter_diamond = 0
    end

    --设置离桌携带量
    if not tableobj.conf.leave_diamond or tableobj.conf.leave_diamond < 0 then
        tableobj.conf.leave_diamond = 0
    end

    --设置自摸加倍模式,默认加底
    if not tableobj.conf.zimo_add_multi_mode or tableobj.conf.zimo_add_multi_mode <= 0 then
        tableobj.conf.zimo_add_multi_mode = EMJZiMoAddMultiMode.ADD_BASE
    end

    --设置封顶倍数,默认8倍
    if not tableobj.conf.max_multi_num or tableobj.conf.max_multi_num <= 0 then
        tableobj.conf.max_multi_num = 8
    end
    
    tableobj.conf.max_player_num = tableobj.conf.max_player_num or 4

    --二人麻将不定缺
    if tableobj.conf.max_player_num == 2 then
        tableobj.is_dingque = false
    end

    --四人麻将才换三张
    if tableobj.conf.max_player_num ~= 4 then
        tableobj.is_huansanzhang = false
    end

    --是否7张
    if tableobj.conf.is_7zhang == true then
        tableobj.is_7zhang = true
    end

    --添加座位
	local seat
	local count = 1
	while count <= conf.max_player_num do
		seat = { }
        seatlogic.init_data(seat,count)
		table.insert(tableobj.seats, seat) --初始化座位数据
		count = count + 1
	end

    --初始游戏数据
	tableobj.gameobj = {tableobj = {}, stateevent = {}}
	gamelogic.init_data(tableobj.gameobj, tableobj)

	gamelogic.wait_player_sitdown(tableobj.gameobj)

	return true
end

---------------------------------------------------------
--处理客户端请求
--

--
-- 进桌
-- 客户端进桌请求最终在这里处理
-- tableobj：桌子对象
-- request：请求包
-- seat： 座位对象，nil or 非nil，由此判断是否重进桌子？
--
function TableLogic.entertable(tableobj, rid, roledata, request, seat)
    local playerinfo = roledata.info
    local playermoney = roledata.money

    --处理重进桌子
	if seat then
		seat.is_leave = false
		local noticemsg = {
			rid = seat.rid,
			seat_index = seat.index,	
		}
		TableLogic.sendmsg_to_alltableplayer(tableobj,"reentertableN", noticemsg)
		if not tableobj.is_had_start then
			if tableobj.delete_table_timer_id > 0 then
				timer.cleartimer(tableobj.delete_table_timer_id)
				tableobj.delete_table_timer_id = -1
			end
		end
	else    --新进入桌子

        --先加入等待玩家列表，并设置相关信息
		local waitinfo = tableobj.waits[rid]
        if waitinfo == nil then
			waitinfo = {}
			waitinfo.playerinfo = {}
			tableobj.waits[rid] = waitinfo
			tableobj.cur_watch_playernum = tableobj.cur_watch_playernum + 1			 
        end

		waitinfo.rid = rid
        waitinfo.playerinfo.diamond = playermoney.diamond
        waitinfo.is_robot = roledata.is_robot
        --暂不支持旁观，超过10s未坐下，则踢出
        waitinfo.watch_timer_id = timer.settimer(10 * 100,"do_watch",{rid = rid, diamond = playermoney.diamond})
	end

    --如果正在删除桌子，停止删除
	if tableobj.delete_table_timer_id > 0 then
		timer.cleartimer(tableobj.delete_table_timer_id)
		tableobj.delete_table_timer_id = -1
	end

    if tableobj.sitdown_player_num <= 0 then
        tableobj.state = EMJTableState.TABLE_STATE_WAIT_PLAYER_SITDOWN
    end
end

--
--坐下
--
function TableLogic.sitdowntable(tableobj, rid, request, seat,roledata)
    local playerinfo = roledata.info
    local playermoney = roledata.money

    --清空旁观超时计时器
    local waitinfo = tableobj.waits[rid] or {}
    if waitinfo.watch_timer_id and waitinfo.watch_timer_id > 0 then
        timer.cleartimer(waitinfo.watch_timer_id)
    end
    tableobj.waits[rid] = nil
    tableobj.cur_watch_playernum = tableobj.cur_watch_playernum - 1

    --初始化seat数据
	seat.rid = rid
	seat.playerinfo.rolename = playerinfo.rolename or ""
	seat.playerinfo.logo = playerinfo.logo or ""
	seat.playerinfo.sex = playerinfo.sex or 0
	seat.playerinfo.ip_addr = roledata.ip_addr or playerinfo.ip_addr
    seat.playerinfo.gps_addr = roledata.gps_addr or playerinfo.gps_addr
    seat.playerinfo.recommrid =  playerinfo.recommrid           --推荐人rid
	seat.playerinfo.agencyrid =  playerinfo.agencyrid           --代理rid
	seat.playerinfo.agencylevel =  playerinfo.agencylevel or 0  --代理等级，0表示不是代理
    seat.playerinfo.level = playerinfo.level or 0
    seat.playerinfo.intro = playerinfo.intro or ""
    seat.playerinfo.upvoted_num = playerinfo.upvoted_num
    seat.playerinfo.downvoted_num = playerinfo.downvoted_num
    seat.playerinfo.logoframe = playerinfo.logoframe

	seat.state = EMJSeatState.SEAT_STATE_WAIT_READY
	seat.playerinfo.coin = playermoney.coin or 0
    seat.playerinfo.lock_coin = playermoney.lock_coin or 0
	seat.playerinfo.lottery = playermoney.lottery or 0
	seat.playerinfo.fangka = playermoney.fangka or 0
	seat.playerinfo.diamond = playermoney.diamond or 0
    seat.playerinfo.lock_diamond = playermoney.lock_diamond or 0
	seat.is_disconnected = false
    seat.is_robot = roledata.is_robot or false
    if not roledata.is_robot and  tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
        seat.playerinfo.dou = 100000
    end

	tableobj.state = EMJTableState.TABLE_STATE_WAIT_ALL_READY
	gamelogic.on_sitdown_table(tableobj.gameobj, seat)

    seat.ready_to_time = seat.ready_to_time or 30        --测试
    seat.ready_timeout_time = timetool.get_time() + seat.ready_to_time

    --通知所有玩家
    if not tableobj.is_matchtable or tableobj.is_had_start then
        -- 给这个玩家发显示“准备”的按钮
	    TableLogic.sendmsg_to_tableplayer(rid, "doreadyN", {action_timeout_time = seat.ready_timeout_time,})

        local noticemsg = {
		    seat_roleinfo = { },
		    seat_gameinfo = { },
	    }
        noticemsg.seat_roleinfo = TableLogic.copy_seat_roleinfo(seat)
        noticemsg.seat_gameinfo = TableLogic.copy_seat_gameinfo(seat)
	    TableLogic.sendmsg_to_alltableplayer(tableobj, "sitdowntableN", noticemsg)
    end

    --设置超时
    local timer_id = timer.settimer(seat.ready_to_time * 100,"doready",{seat_index = seat.index,rid = seat.rid})
    seat.ready_timer_id = timer_id
end

--
--- 准备
-- @param tableobj 牌桌对象
-- @param request 请求数据
-- @param seat 桌位对象
--
function TableLogic.gameready(tableobj, request, seat, roledata)
	if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_ALL_READY then
		return
	end

    --重新匹配状态，点击准备后为其进行匹配
    if tableobj.has_restart_matchtable then
        TableLogic.restart_matchtable(tableobj)
        return
    end

	local noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,
		is_ready = false,
		is_tuoguan = seat.is_tuoguan,
	}

	if seat.state == EMJSeatState.SEAT_STATE_WAIT_START then 
		noticemsg.is_ready = true 
	end
	
	--通知所有玩家
    if not tableobj.is_matchtable or tableobj.is_had_start then
	    TableLogic.sendmsg_to_alltableplayer(tableobj, "gamereadyN", noticemsg)
    else
        seat.is_disconnected = true --状态置为断线，等待客户端重连
    end

	local isallready = true
	local playernum = 0
	for k, v in pairs(tableobj.seats) do
		if not seatlogic.is_empty(v) then
			if v.state ~= EMJSeatState.SEAT_STATE_WAIT_START then
				isallready = false
				break
			end
			playernum = playernum + 1
		end
	end

    if isallready and playernum == tableobj.conf.max_player_num 
    and tableobj.state == EMJTableState.TABLE_STATE_WAIT_ALL_READY then		
		if tableobj.is_had_start then
			tableobj.state = EMJTableState.TABLE_STATE_ONE_GAME_START			
		else
			--当前不支持旁观，踢出旁观玩家
			local waits = tabletool.deepcopy(tableobj.waits)
			for rid, waitinfo in pairs(waits) do
				TableLogic.passive_leavetable(tableobj, rid,waitinfo.playerinfo.diamond)
			end

			--匹配场等待3s
            if tableobj.is_matchtable then
                tableobj.is_ingame = true
                tableobj.state = EMJTableState.TABLE_STATE_WAIT_GAME_START
                timer.settimer(3 * 100,"wait_gamestart")
            else
                tableobj.state = EMJTableState.TABLE_STATE_GAME_START
            end
		end
		gamelogic.run(tableobj.gameobj)
	end
end

--
-- 换三张操作
--
function TableLogic.huansanzhang(tableobj,rid, request,seat)
    if tableobj.huansanzhang_list == nil then
        return
    end

    if not seat.had_huansanzhang then
        tableobj.huansanzhang_list[seat.index] = tabletool.deepcopy(request.exchange_cards)
        seat.had_huansanzhang = true
    else
        return
    end

    local isall = true
    for _,tmpseat in pairs(tableobj.seats) do
        if not tmpseat.had_huansanzhang then
            isall = false
            break
        end
    end

    if isall then
        tableobj.state = EMJTableState.TABLE_STATE_CONTINUE_HUANSANZHANG
        if tableobj.timer_id > 0 then
            timer.cleartimer(tableobj.timer_id)
            tableobj.timer_id = -1
        end
	    gamelogic.run(tableobj.gameobj)
    end
end

--
-- 定缺操作
--
function TableLogic.dingque(tableobj,rid, request,seat)
    if not seat.que_cardcolor then
        seat.que_cardcolor = request.que_color - 1
        tableobj.que_color_list[seat.index] = request.que_color - 1
    else
        return
    end

    local isall = true
    for _,tmpseat in pairs(tableobj.seats) do
        if tmpseat.que_cardcolor == nil then
            isall = false
            break
        end
    end

    if isall then
        tableobj.state = EMJTableState.TABLE_STATE_CONTINUE_DINGQUE
        if tableobj.timer_id > 0 then
            timer.cleartimer(tableobj.timer_id)
            tableobj.timer_id = -1
        end
	    gamelogic.run(tableobj.gameobj)
    end
end

--
-- doaction操作
--
function TableLogic.doaction(tableobj, rid, request, seat)
	local player_action = tableobj.action_player_list[rid]

    --摸牌，改为过牌
    if request.action_type == EMJActionType.MJ_ACTION_TYPE_MOPAI then
        request.action_type = EMJActionType.MJ_ACTION_TYPE_GUO
    end

	player_action.action_type = request.action_type
	if request.action_type == EMJActionType.MJ_ACTION_TYPE_CHUPAI 
    or request.action_type == EMJActionType.MJ_ACTION_TYPE_GANG_CHUPAI then
        if cardtool.check_card(seat.cards, request.card, seat.que_cardcolor) then
		    tableobj.chu_mo_pai_card = request.card
        else
            player_action.action_state = EMJActionState.NODO
            return false,"出牌错误！"
        end
	end

    --暗杠,添杠必须发来要杠的牌
    if request.action_type == EMJActionType.MJ_ACTION_TYPE_ANGANG 
    or request.action_type == EMJActionType.MJ_ACTION_TYPE_BAGANG  then
        if request.card == nil or request.card <= 0 then
            player_action.action_state = EMJActionState.NODO
            return false,"杠牌不能为空！"
        end
        tableobj.curr_actionplayer_cards = {[1] = request.card}
    end

	if seat ~= nil then
        if seat.tuoguan_doaction_timerid and seat.tuoguan_doaction_timerid > 0 then
            timer.cleartimer(seat.tuoguan_doaction_timerid)
		    seat.tuoguan_doaction_timerid = -1
        end
	end

    player_action.action_state = EMJActionState.DOING
	tableobj.curr_actionplayer_rid = rid
	tableobj.curr_actionplayer_cardcolor = seat.que_cardcolor
	
	tableobj.state = EMJTableState.TABLE_STATE_CONTINUE
	gamelogic.run(tableobj.gameobj)

    return true
end

--
--主动离桌
--
function TableLogic.leavetable(tableobj, request,rid,diamond)
    local leavetablemsg = {
        rid = rid,
		table_index = tableobj.index,
	}

    if tableobj.waits[rid] ~= nil then
		TableLogic.sendmsg_to_alltableplayer(tableobj, "leavetableN", leavetablemsg)
		tableobj.cur_watch_playernum = tableobj.cur_watch_playernum - 1
        --通知router,删除rid-table的映射,并通知gate
        skynet.send(".router","lua","leave_table",nil,rid,tableobj.index,diamond)
	end
    tableobj.waits[rid] = nil

    --重置桌子数据
    if tableobj.is_had_start then
        gamelogic.reset_tabledata(tableobj.gameobj)
    end

     --练习场
    if tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
        if tableobj.state ~= EMJTableState.TABLE_STATE_DISBAND_GAME 
        and tableobj.state ~= EMJTableState.TABLE_STATE_UNKNOW then
            TableLogic.disbandtable(tableobj)
            skynet.send(".router","lua","cmd","add_to_idle_practice_table",tableobj.index)
            tableobj.curr_to_num = 0
            tableobj.is_had_start = false
        end
        return
    end

    --匹配场
    if tableobj.is_matchtable then
        if tableobj.is_had_start and tableobj.state ~= EMJTableState.TABLE_STATE_DISBAND_GAME 
        and tableobj.state ~= EMJTableState.TABLE_STATE_UNKNOW then
            tableobj.is_had_start = false
            TableLogic.restart_matchtable(tableobj) --匹配场，将座位上玩家，加入匹配队列
            --TableLogic.disbandtable(tableobj)
            tableobj.curr_to_num = 0
            --tableobj.cur_watch_playernum = 0
            --tableobj.sitdown_player_num = 0
        else
            if tableobj.sitdown_player_num <= 0 then
			    TableLogic.disbandtable(tableobj)
                tableobj.cur_watch_playernum = 0
                tableobj.sitdown_player_num = 0
                tableobj.has_restart_matchtable = nil
                if tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
                    skynet.send(".router","lua","coinmatch","del_from_full_match_table",tableobj.index,tableobj.match_type)
                    skynet.send(".router","lua","coinmatch","add_to_idle_match_table",tableobj.index,tableobj.match_type)
                else
                    skynet.send(".router","lua","match","del_from_full_match_table",tableobj.index,tableobj.match_type)
                    skynet.send(".router","lua","match","add_to_idle_match_table",tableobj.index,tableobj.match_type)
                end
            end
        end
        return
    end

	if tableobj.is_had_start then
        --第一局中
		if tableobj.curr_to_num == 1 and tableobj.is_ingame then
			if tableobj.sitdown_player_num <= 0 then
				if tableobj.delete_table_timer_id > 0 then
					timer.cleartimer(tableobj.delete_table_timer_id)
					tableobj.delete_table_timer_id = -1
				end
 				tableobj.delete_table_timer_id = timer.settimer(100, "delete_table")   --倒计时删除桌子
			end
			return			
		end

		if tableobj.sitdown_player_num <= 0 then
			if tableobj.delete_table_timer_id > 0 then
				timer.cleartimer(tableobj.delete_table_timer_id)
				tableobj.delete_table_timer_id = -1
			end
			tableobj.delete_table_timer_id = timer.settimer(100, "delete_table")
		end
	else
		if tableobj.sitdown_player_num <= 0 and tableobj.cur_watch_playernum <= 0 then
			if tableobj.delete_table_timer_id > 0 then
				timer.cleartimer(tableobj.delete_table_timer_id)
				tableobj.delete_table_timer_id = -1
			end
			tableobj.delete_table_timer_id = timer.settimer(100, "delete_table")
		end
	end
end

--
--- 被动离桌
-- @param tableobj
-- @param rid
-- @param is_leave
--被动离开桌子，使用该接口时玩家必须是在旁观中
--记住使用者如果循环遍历旁观队列一定要使用原队列的copy队列
--
function TableLogic.passive_leavetable(tableobj, rid, diamond, is_leave)
	local leavetablemsg = {
        rid = rid,
		table_index = tableobj.index,
	}

	if tableobj.waits[rid] ~= nil then
		TableLogic.sendmsg_to_alltableplayer(tableobj, "leavetableN", leavetablemsg)
		tableobj.cur_watch_playernum = tableobj.cur_watch_playernum - 1
        --通知router,删除rid-table的映射,并通知gate
        if not is_leave then
            skynet.send(".router","lua","leave_table",nil,rid,tableobj.index,diamond)
        end
	end
	tableobj.waits[rid] = nil

    --桌子正在删除直接返回
	if tableobj.isdeleting then
		return
	end

    --重置桌子数据
    if tableobj.is_had_start then
        gamelogic.reset_tabledata(tableobj.gameobj)
    end

     --练习场
    if tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
         skynet.send(".router","lua","cmd","add_to_idle_practice_table",tableobj.index)
         tableobj.curr_to_num = 0
         tableobj.is_had_start = false
         return
    end

    --匹配场
    if tableobj.is_matchtable then
        if tableobj.is_had_start and tableobj.state ~= EMJTableState.TABLE_STATE_DISBAND_GAME 
        and tableobj.state ~= EMJTableState.TABLE_STATE_UNKNOW then
            tableobj.is_had_start = false
            TableLogic.restart_matchtable(tableobj) --匹配场，将座位上玩家，加入匹配队列
            --TableLogic.disbandtable(tableobj)
            tableobj.curr_to_num = 0
            --tableobj.cur_watch_playernum = 0
            --tableobj.sitdown_player_num = 0
        else
            if tableobj.sitdown_player_num <= 0 then
			    TableLogic.disbandtable(tableobj)
                tableobj.cur_watch_playernum = 0
                tableobj.sitdown_player_num = 0
                tableobj.has_restart_matchtable = nil
                if tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
                    skynet.send(".router","lua","coinmatch","del_from_full_match_table",tableobj.index,tableobj.match_type)
                    skynet.send(".router","lua","coinmatch","add_to_idle_match_table",tableobj.index,tableobj.match_type)
                else
                    skynet.send(".router","lua","match","del_from_full_match_table",tableobj.index,tableobj.match_type)
                    skynet.send(".router","lua","match","add_to_idle_match_table",tableobj.index,tableobj.match_type)
                end
            end
        end
        return
    end

    --游戏已经开始
	if tableobj.is_had_start then
        --第一局中
		if tableobj.curr_to_num == 1 and tableobj.is_ingame then
			if tableobj.sitdown_player_num <= 0 then
				if tableobj.delete_table_timer_id > 0 then
					timer.cleartimer(tableobj.delete_table_timer_id)
					tableobj.delete_table_timer_id = -1
				end
                --被动解散
 				tableobj.delete_table_timer_id = timer.settimer(100, "delete_table")
			end
			return			
		end

        --第一局结局或之后
		if tableobj.sitdown_player_num <= 0 then
			if tableobj.delete_table_timer_id > 0 then
				timer.cleartimer(tableobj.delete_table_timer_id)
				tableobj.delete_table_timer_id = -1
			end
			tableobj.delete_table_timer_id = timer.settimer(100, "delete_table")
		end
	else    --未开始，直接删除
        --桌内没有玩家，倒计时删除桌子
		if tableobj.sitdown_player_num <= 0 and tableobj.cur_watch_playernum <= 0 then
			if tableobj.delete_table_timer_id > 0 then
				timer.cleartimer(tableobj.delete_table_timer_id)
				tableobj.delete_table_timer_id = -1
			end
			tableobj.delete_table_timer_id = timer.settimer(100, "delete_table")
		end
	end
end

--
-- 游戏中离桌
--
function TableLogic.leavegame(tableobj, request, seat)
    if seat == nil or seat.has_leave then
        return
    end

   --游戏中退出,立即对该玩家进行结算
    if tableobj.is_ingame then
        if not seatlogic.is_empty(seat) and seat.is_hupai and seat.is_can_half_leave then  --胡牌的玩家才能退出
            if tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
                gamelogic.game_half_coin(tableobj.gameobj,seat)
            else
                gamelogic.game_half_diamond(tableobj.gameobj,seat)
            end
        end

        --通知gate
        skynet.send(".router","lua","leave_table",nil,seat.rid,tableobj.index,seat.playerinfo.diamond)
        seat.has_leave = true   --设置离桌标记

        --通知其他玩家
        local noticemsg = {
            rid = seat.rid,
            seat_index = seat.index,
        }

        TableLogic.sendmsg_to_alltableplayer(tableobj, "leavegameN", noticemsg)
    end
end

--
-- 被动站起
--
function TableLogic.passive_standuptable(tableobj, request, seat, reason, is_sendto_client)
	tableobj.sitdown_player_num = tableobj.sitdown_player_num - 1 
	local standuptablemsg = {
		rid = seat.rid,
		seat_index = seat.index,
		table_index = tableobj.index,
        reason = reason,
	}

    --通知客户端
	TableLogic.sendmsg_to_alltableplayer(tableobj, "standuptableN", standuptablemsg)
	seat.state = EMJSeatState.SEAT_STATE_NO_PLAYER

    --保存进旁观列表
	if tableobj.waits[seat.rid] == nil then
		local waitinfo = {
			playerinfo = {},
		}
		tableobj.waits[seat.rid] = waitinfo
		waitinfo.rid = seat.rid
        waitinfo.playerinfo.diamond = seat.playerinfo.diamond

		tableobj.cur_watch_playernum = tableobj.cur_watch_playernum + 1
	end

	---
	--初始化座位数据
	gamelogic.standup_clear_seat(tableobj.gameobj, seat)
end

--
-- 主动站起
--
function TableLogic.standuptable(tableobj, request, seat)
	tableobj.sitdown_player_num = tableobj.sitdown_player_num - 1
	local noticemsg = {
		rid = seat.rid, 
		seat_index = seat.index,
		table_index = tableobj.index,
		reason = EStandupReason.STANDUP_REASON_ONSTANDUP,
	}

	if tableobj.state == EMJTableState.TABLE_STATE_UNKNOW then
		TableLogic.sendmsg_to_tableplayer(seat.rid, "standuptableN", noticemsg)
	else
		TableLogic.sendmsg_to_alltableplayer(tableobj, "standuptableN", noticemsg)
	end

	seat.state = EMJSeatState.SEAT_STATE_NO_PLAYER
	if tableobj.waits[seat.rid] == nil then
		local waitinfo = {
			playerinfo = {},
		}
		tableobj.waits[seat.rid] = waitinfo
		waitinfo.rid = seat.rid
        waitinfo.playerinfo.diamond = seat.playerinfo.diamond

		tableobj.cur_watch_playernum = tableobj.cur_watch_playernum + 1
	end

	--初始化座位数据
	gamelogic.standup_clear_seat(tableobj.gameobj, seat)
end

--
--  所有玩家离桌
--
function TableLogic.leavetableallplayer(tableobj,reason)
    if type(tableobj.seats) ~= "table" then
        return
    end
	for _, seat in pairs(tableobj.seats) do
		if not seatlogic.is_empty(seat) then
            local rid,diamond = seat.rid,seat.playerinfo.diamond
            local is_leave = seat.has_leave
			TableLogic.passive_standuptable(tableobj, nil, seat, reason)
			TableLogic.passive_leavetable(tableobj,rid,diamond, is_leave)
		end
	end
end

--- 断线重连处理函数
-- @param tableobj
-- @param request
-- @param seat
--
function TableLogic.reentertable(tableobj, request, seat)
	local noticemsg
	local player_action
	local tmpseat
    local cur_player_action

    --更改断线状态
    if seat.is_disconnected then
	    seat.is_disconnected = false
    end

    --首先判断是否一局结束
	if not TableLogic.is_onegameend(tableobj) then
		if tableobj.state == EMJTableState.TABLE_STATE_WAIT_MJ_SHAKE_DICE then  --摇骰子中
            local banker_seat = tableobj.seats[tableobj.banker_seat_index]
			noticemsg = {
				rid = banker_seat.rid,
				seat_index = banker_seat.index,
				dice_one = tableobj.dice_one,		
				dice_two = tableobj.dice_two,
			}
			TableLogic.sendmsg_to_tableplayer(seat.rid, "shakediceN", noticemsg)			
		end

        if tableobj.state == EMJTableState.TABLE_STATE_WAIT_MJ_HUAN_SAN_ZHANG then  --换三张中
            local suggest_cards = tableobj.huansanzhang_list[seat.index]
            if suggest_cards == nil then
                suggest_cards = cardtool.get_exchange_cards(seat.cards)
                tableobj.huansanzhang_list[seat.index] = tabletool.deepcopy(suggest_cards)
            end
			noticemsg = {
                rid = seat.rid,
                seat_index = seat.index,
                suggest_cards =  suggest_cards,
                action_timeout_time = tableobj.action_timeout_time,
            }
			TableLogic.sendmsg_to_tableplayer(seat.rid, "huansanzhangN", noticemsg)			
		end

        if tableobj.state == EMJTableState.TABLE_STATE_WAIT_MJ_DINGQUE then  --定缺中
            local que_color = tableobj.que_color_list[seat.index] 
            if que_color == nil then
                que_color = cardtool.get_suggest_que(seat.cards)
                tableobj.que_color_list[seat.index] = que_color
            end
			noticemsg = {
                rid = seat.rid,
                seat_index = seat.index,
                suggest_que_color = que_color + 1,
                action_timeout_time = tableobj.action_timeout_time,
            }
			TableLogic.sendmsg_to_tableplayer(seat.rid, "dingqueN", noticemsg)			
		end

        --发牌中，则重新通知发牌
		if tableobj.state == EMJTableState.TABLE_STATE_MJ_DEAL_CARDS and #(seat.cards) > 0 then
			noticemsg = {
				rid = seat.rid,
				seat_index = seat.index,
				cards = seat.cards, --手牌
				remain_card_num = tableobj.cards_stack.cur_num   --牌堆牌数
			}
			TableLogic.sendmsg_to_tableplayer(seat.rid, "dealcardsN", noticemsg)   --发牌消息
		end

        --解散桌子请求中，发送解散桌子消息
        if tableobj.playerdisbandlist ~= nil then
            local launch_player_seat = tableobj.seats[tableobj.disband_player_index]
            noticemsg = {
			    rid = launch_player_seat.rid,
			    seat_index = launch_player_seat.index,
			    action_timeout_time = tableobj.disband_timeout_time,
			    apply_player_name = launch_player_seat.playerinfo.rolename,
		    }
            noticemsg.player_disband_list = tabletool.deepcopy(tableobj.playerdisbandlist)
		    TableLogic.sendmsg_to_tableplayer(seat.rid, "disbandtableN", noticemsg)
        end

        --操作列表不为空，则继续处理
        if tableobj.action_player_list ~= nil then
            player_action =  tableobj.action_player_list[seat.rid]
            if player_action == nil then
                if tableobj.state == EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION then --等待杠碰胡出牌中
                    local noticemsgs = { }
                    for _,tmpplayer_action in pairs(tableobj.action_player_list) do
                        if tmpplayer_action.action_state == EMJActionState.NODO then
                            noticemsg = {
				                rid = tmpplayer_action.rid,
				                seat_index = tmpplayer_action.seat_index,
				                action_timeout_time = tableobj.action_timeout_time,
				                wait_action_type = tmpplayer_action.action_type,
                                remain_card_num = tableobj.cards_stack.cur_num,
			                }
                            if tableobj.chu_mo_pai_seat_index ~= tmpplayer_action.seat_index and
                            tmpplayer_action.action_type == EMJActionType.MJ_ACTION_TYPE_SELECT then
                                noticemsg.card = tableobj.chu_mo_pai_card
                            end
                            table.insert(noticemsgs,noticemsg)
                        end
                    end

                    if #noticemsgs > 0 then
                        TableLogic.sendmsg_to_tableplayer(seat.rid, "todoN", {todo_list = noticemsgs})
                    end
                end
            else
		        --轮到自己操作			
		        if player_action.action_state == EMJActionState.NODO then
			        noticemsg = {
				        rid = player_action.rid,
				        seat_index = player_action.seat_index,
				        action_timeout_time = tableobj.action_timeout_time,
				        wait_action_types = player_action.wait_action_types,
				        card = tableobj.chu_mo_pai_card,
                        remain_card_num = tableobj.cards_stack.cur_num,
                        chupai_seat_index = tableobj.chu_mo_pai_seat_index,
			        }
			        TableLogic.sendmsg_to_tableplayer(seat.rid, "todoN", {todo_list = {noticemsg}})
		        end
		    end
        end
	end

    --更改离开状态，通知所有玩家
	if seat.is_leave then
		seat.is_leave = false
		local noticemsg = {
			rid = seat.rid,
			seat_index = seat.index,	
		}
		TableLogic.sendmsg_to_alltableplayer(tableobj,"reentertableN", noticemsg)
	end

    --通知玩家，哪些人离线
    --[[
	local playerleavemsg = {}
	for _, tmpseat in pairs(tableobj.seats) do
		if not seatlogic.is_empty(tmpseat) and tmpseat.is_disconnected then
			playerleavemsg.rid = tmpseat.rid
			playerleavemsg.seat_index = tmpseat.index	
			TableLogic.sendmsg_to_tableplayer(seat.rid, "disconnectN", playerleavemsg)
		end
	end
    ]]

    --等待准备,则发送准备
	if tableobj.state == EMJTableState.TABLE_STATE_WAIT_ALL_READY 
		and seat.state == EMJSeatState.SEAT_STATE_WAIT_READY then
		seat.state = EMJSeatState.SEAT_STATE_WAIT_READY
        TableLogic.sendmsg_to_tableplayer(seat.rid, "doreadyN", {action_timeout_time = seat.ready_timeout_time})
	end
end

--
--开始游戏
--
function TableLogic.startgame(tableobj, request)
    --检测是否能开始
	if TableLogic.is_canstartgame(tableobj) then
			tableobj.state = EMJTableState.TABLE_STATE_GAME_START
		gamelogic.run(tableobj.gameobj) --开始run
	else
		--table_data.state = ENNTableState.TABLE_STATE_WAIT_MIN_PLAYER
	end
end

function TableLogic.disbandtable(tableobj)
    --保存游戏记录
    local reason = 0
    if TableLogic.is_onegameend(tableobj) then
        if tableobj.curr_to_num == 0 then
            reason = EMJTableDeleteReason.DELETE_REASON_FIRST_START_BEFORE_DISBAND
        else
            reason = EMJTableDeleteReason.DELETE_REASON_ONE_START_BEFORE_DISBAND
        end
    else
        reason = EMJTableDeleteReason.DELETE_REASON_IN_GAME_DISBAND
    end
    tableobj.game_records.delete_reason = reason
    tableobj.state = EMJTableState.TABLE_STATE_DISBAND_GAME
	gamelogic.run(tableobj.gameobj)
end


--------------------------------------------
--send方法
--

--
-- 通知桌上所有玩家
--
function TableLogic.sendmsg_to_alltableplayer( tableobj, msgname, message)
    local retcode,retstr,msgbody
    if message and message.retcode  then
		retcode = tonumber(message.retcode)
		retstr = message.retstr or ""
		msgbody = message.msgbody or { }
    else
        msgbody = message
	end

    local rids = { }
    local seats = tableobj.seats
    for i,seat in pairs(seats) do
       if not seatlogic.is_empty(seat) and  not seat.is_disconnected 
       and not seat.is_robot and not seat.has_leave then
            table.insert(rids,seat.rid)
       end 
    end

    if tableobj.waits ~= nil then
        for i,wait in pairs(tableobj.waits) do
            if not wait.is_robot then
                table.insert(rids,wait.rid)
            end
        end
    end
    
    service:send_notice_to_players(rids, msgname, msgbody, retcode, retstr)
end

--
-- 通知桌上除某玩家之外的所有玩家
-- rid 排除的玩家
--
function TableLogic.sendmsg_to_otheralltableplayer( tableobj,rid, msgname, message)
    local retcode,retstr,msgbody
    if message and message.retcode  then
		retcode = tonumber(message.retcode)
		retstr = message.retstr or ""
		msgbody = message.msgbody or { }
    else
        msgbody = message
	end

    local rids = { }
    local seats = tableobj.seats
    for i,seat in pairs(seats) do
       if not seatlogic.is_empty(seat) and seat.rid ~= rid and not 
       seat.is_disconnected and not seat.is_robot and not seat.has_leave then
            table.insert(rids,seat.rid)
       end 
    end

     if tableobj.waits ~= nil then
        for i,wait in pairs(tableobj.waits) do
            if wait.rid ~= rid and not wait.is_robot then
                table.insert(rids,wait.rid)
            end
        end
    end
    
    
    service:send_notice_to_players(rids, msgname, msgbody, retcode, retstr)
end

--
-- 通知桌上某个玩家
--
function TableLogic.sendmsg_to_tableplayer( rid, msgname, message)
    local seat = TableLogic.get_seat_by_rid(service.table_data,rid) or {}
    if seat.is_disconnected or seat.is_robot or seat.has_leave then
        return
    end

    local retcode,retstr,msgbody
    if message and message.retcode  then
		retcode = tonumber(message.retcode)
		retstr = message.retstr or ""
		msgbody = message.msgbody or { }
    else
        msgbody = message
	end

    local rids = { }
    table.insert(rids,rid) 
    service:send_notice_to_players(rids, msgname, msgbody, retcode, retstr)
end

--
-- 通知所有旁观列表玩家
--

function TableLogic.sendmsg_to_allwaitplayer(tableobj, msgname, message)
    local retcode,retstr,msgbody
    if message and message.retcode  then
		retcode = tonumber(message.retcode)
		retstr = message.retstr or ""
		msgbody = message.msgbody or { }
    else
        msgbody = message
	end

    local rids = { }
    local waits = tableobj.waits
    for i,wait in pairs(waits) do
       if wait.rid and not wait.is_robot then
            table.insert(rids,wait.rid)
       end 
    end
    
    service:send_notice_to_players(rids, msgname, msgbody, retcode, retstr)
end

--
-- 更新桌子心跳时间
--
function TableLogic.update_table_heart_time(tableobj)
    tableobj.last_heart_time = timetool.get_time()
end

--
-- 设置所有座位
--
function TableLogic.setallseatstate(tableobj, state)
	for k,value in pairs(tableobj.seats) do
		value.state = state
	end
end


--------------------------------------------
--金钱相关

--
-- 钻石场扣服务费
-- rid_value {beginvalue,value,endvalue,rolename}
--
function TableLogic.game_sub_fuwufei(rid_values)
    local comment = TableLogic.create_comment()
    local status,result = skynet.pcall(cluster.call,"gatenode", ".router", "game_sub_fuwufei", rid_values, comment) 
    if not status then
        filelog.sys_error("game_sub_fuwufei call failed!")
        return false
    end
    return result,comment
end

--
-- 金币场扣服务费
-- rid_value {beginvalue,value,endvalue,rolename}
--
function TableLogic.game_sub_coin(rid_values)
    local comment = TableLogic.create_comment()
    local status,result = skynet.pcall(cluster.call,"gatenode", ".router", "game_sub_coin", rid_values, comment) 
    if not status then
        filelog.sys_error("game_sub_coin call failed!")
        return false
    end
    return result,comment
end


--
-- 中途退出扣钻石
-- rid_value {beginvalue,value,endvalue,rolename,had_half}
--
function TableLogic.game_half_diamond(rid_values)
    local comment = TableLogic.create_comment()
    local status,result = skynet.pcall(cluster.call,"gatenode", ".router", "game_half_diamond", rid_values, comment)
    if not status then
        filelog.sys_error("game_half_diamond call failed!")
        return false
    end
    return result,comment
end

--
-- 结算后钻石信息，每局结算都要通知gate
-- rid_value {beginvalue,value,endvalue,rolename,had_half}
--
function TableLogic.game_balance_diamond(rid_values)
    local comment = TableLogic.create_comment()
    local status,result = skynet.pcall(cluster.call,"gatenode", ".router", "game_balance_diamond", rid_values, comment)
    if not status then
        filelog.sys_error("game_balance_diamond call failed!")
        return false
    else
        --记录流水日志
        for rid,item in pairs(rid_values) do
            --记录流水变化值
            local chg_logstr = string.format("%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s", EDiamondChange.FUWUFEI, rid, item.level, item.real_change, 
            item.beginvalue,item.endvalue, 0, 0, 0, comment.table_uuid, comment.start_time, comment.table_tradeid)
            if tonumber(item.real_change) ~= tonumber(0) then
                skynet.send(".diamondlog", "lua", "write_file_redis", chg_logstr, rid)
            else
                skynet.send(".diamondlog", "lua", "write", chg_logstr)
            end
        end
    end
    return result,comment
end

--
-- 中途退出扣金币
-- rid_value {beginvalue,value,endvalue,rolename,had_half}
--
function TableLogic.game_half_coin(rid_values)
    local comment = TableLogic.create_comment()
    local status,result = skynet.pcall(cluster.call,"gatenode", ".router", "game_half_coin_diamond", rid_values, comment)
    if not status then
        filelog.sys_error("game_half_diamond call failed!")
        return false
    end
    return result,comment
end

--
-- 结算后金币信息，每局结算都要通知gate
-- rid_value {beginvalue,value,endvalue,rolename,had_half}
--
function TableLogic.game_balance_coin(rid_values)
    local comment = TableLogic.create_comment()
    local status,result = skynet.pcall(cluster.call,"gatenode", ".router", "game_balance_coin_diamond", rid_values, comment)
    if not status then
        filelog.sys_error("game_balance_coin call failed!")
        return false
    end
    return result,comment
end

--
-- 房卡场游戏结算
-- rid_value {beginvalue,value,endvalue,rolename}
--
function TableLogic.game_balance_fangka(rid_values)
    local comment = TableLogic.create_comment()
    local status,result = skynet.pcall(cluster.call,"gatenode", ".router", "game_balance_fangka", rid_values, comment)
    if not status then
        filelog.sys_error("game_balance_fangka call failed!")
        return false
    end
    return result,comment
end

--
-- 扣房卡
-- rid_value {beginvalue,value,endvalue,rolename}
--
function TableLogic.game_sub_fangka(rid_values)
    local comment = TableLogic.create_comment()
    local status,result = skynet.pcall(cluster.call,"gatenode", ".router", "game_sub_fangka", rid_values, comment) 
    if not status then
        filelog.sys_error("game_sub_fangka call failed!")
        return false
    end
    return result,comment
end

--
--  改变金钱
--
function TableLogic.change_money(rid, itemvalues)
    local comment = TableLogic.create_comment()
    local status,result = skynet.pcall(cluster.call,"gatenode", ".router", "change_money", rid, itemvalues, comment)
    if not status then
        filelog.sys_error("change_money call failed!")
        return false
    end
    return result,comment
end

--------------------------------------------
--get方法
--

--
--根据rid获得座位对象
--
function TableLogic.get_seat_by_rid(tableobj, rid)
	if tableobj.seats == nil then
		return nil
	end

	for index, seat in pairs(tableobj.seats) do
		if rid == seat.rid then
			return seat
		end
	end
	return nil
end

--- 根据玩家的rid查找玩家是否在旁观队列
-- @param tableobj 牌桌对象
-- @param rid  玩家rid
function TableLogic.get_waitplayer_by_rid(tableobj, rid)
	for index, waitplayer in pairs(tableobj.waits) do
		if rid == waitplayer.rid then
			return waitplayer
		end
	end
	return nil
end

--
--- 根据指定桌位号获得一张空座位
-- @param tableobj 牌桌对象
-- @param index 座位号
function TableLogic.get_emptyseat_by_index(tableobj, index)
	if index == nil or index <= 0 or index > tableobj.conf.max_player_num then
		for index, seat in pairs(tableobj.seats) do
			if seatlogic.is_empty(seat) then
				return seat
			end
		end
	else
		local seat = tableobj.seats[index]
		if seatlogic.is_empty(seat) then
			return seat
		end
	end
	return nil
end

--
-- 获得桌子索引号
--
function TableLogic.get_table_index(tableobj)
	return tableobj.table_index
end

--
-- 获得坐下玩家数
--
function TableLogic.get_sitdown_player_num(tableobj)
	return tableobj.sitdown_player_num
end

--
-- 获得游戏中玩家数
--
function TableLogic.get_ingame_playernum(tableobj)
	local playernum = 0	
	for _, seat in pairs(tableobj.seats) do
		if gamelogic.is_ingame(tableobj.gameobj, seat) then
			playernum = playernum + 1
		end
	end
	return playernum
end

--------------------------------------------
--is方法
--

--- 判断当前桌子是否坐满
-- @param tableobj  牌桌对象
--
function TableLogic.is_full(tableobj)
	return (tableobj.sitdown_player_num >= tableobj.conf.max_player_num)
end

---判断当前是否能够开始游戏
-- @param tableobj	牌桌对象
--
function TableLogic.is_canstartgame(tableobj)
	return TableLogic.is_full(tableobj) --坐满即可开
end

--- 判断游戏是否结束
-- @param tableobj 牌桌对象
--
function TableLogic.is_gameend(tableobj)
	if tableobj.state == EMJTableState.TABLE_STATE_GAME_END
	or tableobj.state == EMJTableState.TABLE_STATE_WAIT_PLAYER_SITDOWN
	or tableobj.state == EMJTableState.TABLE_STATE_UNKNOW then
		return true
	end

	return false
end

--- 判断当前局是否已经结束游戏
-- @param tableobj 牌桌对象
--
function TableLogic.is_onegameend(tableobj)
	if tableobj.state == EMJTableState.TABLE_STATE_ONE_GAME_REAL_END
	or tableobj.state == EMJTableState.TABLE_STATE_WAIT_ALL_READY then
		return true
	end

	if not tableobj.is_ingame then
		return true
	end

	return TableLogic.is_gameend(tableobj)
end

--- 判断是否所有玩家都已响应解散桌子请求
-- @param tableobj 牌桌对象
--
function TableLogic.is_allplayer_response_disband(tableobj)
    local agree_num = 0
    local refuse_num = 0

    if tableobj.playerdisbandlist == nil then
        return false
    end

    for k,role in pairs(tableobj.playerdisbandlist) do
        if role.is_agree == 1 then
            agree_num = agree_num + 1
        elseif role.is_agree == 2 then
            refuse_num = refuse_num + 1
        elseif role.is_agree == nil then
            return false
        end
    end
    
    return true,agree_num,refuse_num
end

--------------------------------------------
--copy方法
--

--
-- 这是要按照proto来组织，然后返回给客户端
--
function TableLogic.copy_table_gameinfo()
    local table_data = service.table_data
	local gameinfo = {}
	gameinfo.table_baseinfo = {}
	gameinfo.table_conf = tabletool.deepcopy(table_data.conf)
	gameinfo.seat_roleinfos = {}
	gameinfo.seat_gameinfos = {}

	gameinfo.table_baseinfo.uuid = table_data.uuid 
	gameinfo.table_baseinfo.index = table_data.index 
	gameinfo.table_baseinfo.code = table_data.code 
	gameinfo.table_baseinfo.state = table_data.state 
	gameinfo.table_baseinfo.create_rid = table_data.create_rid 
	gameinfo.table_baseinfo.create_rolename = table_data.create_rolename 
	gameinfo.table_baseinfo.create_time = table_data.create_time 
	gameinfo.table_baseinfo.sitdown_player_num = table_data.sitdown_player_num 
	gameinfo.table_baseinfo.curr_to_num = table_data.curr_to_num
    gameinfo.table_baseinfo.service_fee = table_data.service_fee
    gameinfo.table_baseinfo.curr_round_code = table_data.curr_round_code or ""

	for index,seat in pairs(table_data.seats) do
		gameinfo.seat_roleinfos[index] = TableLogic.copy_seat_roleinfo(seat)
		gameinfo.seat_gameinfos[index] = TableLogic.copy_seat_gameinfo(seat)
	end
	return gameinfo
end


--
--拷贝座位游戏信息
--
function TableLogic.copy_seat_gameinfo(seat)
    local seat_gameinfo ={}
    seat_gameinfo.rid		= seat.rid
    seat_gameinfo.index		= seat.index
    seat_gameinfo.state		= seat.state
    seat_gameinfo.offline	= (seat.is_disconnected and 1) or 0
    seat_gameinfo.is_banker = (seat.is_banker and 1) or 0
    seat_gameinfo.card_num	= #seat.cards
    seat_gameinfo.action_to_time = seat.action_timeout_time
    seat_gameinfo.out_cards	= tabletool.deepcopy(seat.out_cards)
    seat_gameinfo.di_cards	= tabletool.deepcopy(seat.di_cards)
    seat_gameinfo.que_cardcolor = seat.que_cardcolor
    seat_gameinfo.diamond = seat.playerinfo.diamond 
    seat_gameinfo.is_tuoguan = seat.is_tuoguan
    seat_gameinfo.ready_timeout_time = seat.ready_timeout_time
    seat_gameinfo.hupai_card = seat.hupai_card
    seat_gameinfo.yinhu_seat_index = seat.yinhu_seat_index
    if seat.has_leave then
        seat_gameinfo.state = EMJSeatState.SEAT_STATE_HAS_LEAVE
    elseif seat.is_hupai then
        seat_gameinfo.state = EMJSeatState.SEAT_STATE_HAS_HUPAI
    end

    seat_gameinfo.score		= seat.curr_score
    if service.table_data.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then
        seat_gameinfo.score		= seat.total_score
    end
    if service.table_data.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
         seat_gameinfo.diamond = seat.playerinfo.dou
         if seat.is_robot then
            seat_gameinfo.is_tuoguan = false
         end 
    end
    if service.table_data.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
         seat_gameinfo.diamond = seat.playerinfo.coin 
    end
    if seat.que_cardcolor then
        seat_gameinfo.que_cardcolor = seat.que_cardcolor + 1
    end

    return seat_gameinfo
end

--
--拷贝座位角色信息
--
function TableLogic.copy_seat_roleinfo(seat)
    local seat_roleinfo = {}
    seat_roleinfo.rid = seat.rid
    seat_roleinfo.rolename = seat.playerinfo.rolename
    seat_roleinfo.logo = seat.playerinfo.logo
    seat_roleinfo.sex = seat.playerinfo.sex
    seat_roleinfo.coin = seat.playerinfo.coin
    seat_roleinfo.diamond = seat.playerinfo.diamond
    seat_roleinfo.fangka = seat.playerinfo.fangka
    seat_roleinfo.intro = seat.playerinfo.intro
    seat_roleinfo.ip_addr = seat.playerinfo.ip_addr
    seat_roleinfo.gps_addr = seat.playerinfo.gps_addr
    seat_roleinfo.upvoted_num = seat.playerinfo.upvoted_num
    seat_roleinfo.downvoted_num = seat.playerinfo.downvoted_num
    seat_roleinfo.logoframe = seat.playerinfo.logoframe
    return seat_roleinfo
end

------------------------------------------------
--其他

--清空桌子对象数据
--
function TableLogic.clear(tableobj)
	if tableobj.timer_id > 0 then
		timer.cleartimer(tableobj.timer_id)
		tableobj.timer_id = -1
	end

	if tableobj.delete_table_timer_id > 0 then
		timer.cleartimer(tableobj.delete_table_timer_id)
		tableobj.delete_table_timer_id = -1
	end

	if tableobj.disband_table_timer_id > 0 then
		timer.cleartimer(tableobj.disband_table_timer_id)
		tableobj.disband_table_timer_id = -1		
	end

	for _, seat in pairs(tableobj.seats) do
		if seat.tuoguan_doaction_timerid ~= -1 then
			timer.cleartimer(seat.tuoguan_doaction_timerid)
			seat.tuoguan_doaction_timerid = -1			
		end
	end

	for k,v in pairs(tableobj) do
		tableobj[k] = nil
	end
end

--
--创建comment
--
function  TableLogic.create_comment()
    local tableobj = service.table_data
    local tradeid = skynet.call(".nodeuuid", "lua", "getuuid")
    local start_time = tableobj.one_start_time or 0
    local is_matchtable = tableobj.is_matchtable
    local replay_logname = nil
    if tableobj.game_records then
        replay_logname = tableobj.game_records.cur_action_record_id
    end
    return {table_uuid = tableobj.uuid ,table_tradeid = tradeid,start_time = start_time, replay_logname = replay_logname, is_matchtable = is_matchtable}
end

--
--断开连接(断线）
--
function TableLogic.disconnect(tableobj, request, seat)
    --保存断线记录
    if not seat.is_disconnected and seat.cards and #(seat.cards) > 0 then
        local cur_time = timetool.get_time()
        local item = tostring(cur_time) .. "_" .. seat.rid .."_" .. "disconnect"
        TableLogic.save_playback_record(item)
    end

	seat.is_disconnected = true
	seat.is_leave = true
	local noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,	
	}

	TableLogic.sendmsg_to_alltableplayer(tableobj,"disconnectN", noticemsg)

    --非匹配钻石场，准备断线，将其踢出桌子
    if not tableobj.is_matchtable 
    and tableobj.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI 
    and tableobj.state == EMJTableState.TABLE_STATE_WAIT_ALL_READY 
    and seat.state == EMJSeatState.SEAT_STATE_WAIT_READY then
        local rid,diamond = seat.rid,seat.playerinfo.diamond
        TableLogic.passive_standuptable(tableobj, {}, seat, EStandupReason.STANDUP_REASON_DISCONNECTED)	
        TableLogic.passive_leavetable(tableobj,rid,diamond)
    end

    --断线超时后会自动托管
    --[[
    if not seat.is_tuoguan then
        TableLogic.dotuoguan(tableobj,{rid = seat.rid,is_tuoguan = true},seat)
    end
    ]]
end

------------------------------------------------------------------------
------------------------------------------------------------------------

--- 保存回放记录
-- @param card_records 
--
function TableLogic.save_playback_record(record,game_records,is_init)
    if service.table_data.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
        return
    end

    local game_records = game_records or service.table_data.game_records
    local record_id = game_records.cur_action_record_id or ""
    if record_id == "" then
        return
    end
    
    local  tablerecords = ""
    if is_init then --初始化
        tablerecords = tablerecords .. game_records.table_uuid .. "\n"                              --桌子唯一id
        tablerecords = tablerecords .. game_records.table_type .. "\n"                              --桌子类型
	    tablerecords = tablerecords .. game_records.service_fee .. "\n"                             --服务费
        tablerecords = tablerecords .. json.encode(game_records.conf) .. "\n"                       --桌子配置
	    tablerecords = tablerecords .. game_records.one_start_time .. "\n"                          --本局开始时间
        tablerecords = tablerecords .. json.encode(game_records.role_info) .. "\n"                  --玩家信息
        tablerecords = tablerecords .. json.encode(game_records.cards_stack)                        --牌堆
    else
        if type(record) == "table" then
            tablerecords = tablerecords .. json.encode(record)
        else
            tablerecords = tablerecords .. record
        end
    end

    --调用日志服务写到文件
	skynet.send(".tablereplaylog", "lua", "write",record_id,tablerecords)
end

--- 保存牌桌每局记录
-- @param game_records 游戏记录
--
function TableLogic.save_table_records(game_records)
    if service.table_data.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
        return
    end

    local tablerecords = ""
    tablerecords = tablerecords .. game_records.table_uuid .. "\n"                                  --桌子唯一id
    tablerecords = tablerecords .. game_records.table_type .. "\n"                                  --桌子类型
	tablerecords = tablerecords .. game_records.service_fee .. "\n"                                 --服务费
    tablerecords = tablerecords .. json.encode(game_records.conf) .. "\n"                           --桌子配置
	tablerecords = tablerecords .. game_records.one_start_time .. "\n"                              --本局开始时间
    tablerecords = tablerecords .. game_records.one_end_time .. "\n"                                --本局结束时间
	tablerecords = tablerecords .. json.encode(game_records.diamond_change_list) .. "\n"            --玩家钻石变化情况
    tablerecords = tablerecords .. json.encode(game_records.coin_change_list) .. "\n"               --玩家钻石变化情况
    tablerecords = tablerecords .. game_records.table_tradeid .. "\n"                               --本局唯一交易id
    tablerecords = tablerecords .. json.encode(game_records.balance_suan_fan_list)                  --本局结算情况

    --调用日志服务写到文件
	skynet.send(".tablerecordlog", "lua", "write",game_records.cur_record_id,tablerecords)
end

--- 保存牌桌最终记录(桌子被删除时）
-- @param tableobj 桌子对象
--
function TableLogic.save_table_final_records(tableobj)
    if tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
        return
    end

    local game_records = tableobj.game_records

    local tablerecords = ""
	tablerecords = tablerecords .. game_records.table_uuid .. "_"           --桌子唯一id
    tablerecords = tablerecords .. game_records.table_type .. "_"           --桌子类型
    tablerecords = tablerecords .. game_records.service_fee .. "_"          --服务费
	tablerecords = tablerecords .. game_records.create_user_rid .. "_"      --创建者rid
	tablerecords = tablerecords .. game_records.create_time .. "_"          --创建时间
    tablerecords = tablerecords .. game_records.delete_time .. "_"          --删除时间
	tablerecords = tablerecords .. game_records.start_time .. "_"           --第一局开始时间
    tablerecords = tablerecords .. game_records.end_time .. "_"             --最后一局结束时间
    tablerecords = tablerecords .. game_records.final_to_num .. "_"         --最终局数
    tablerecords = tablerecords .. game_records.delete_reason or 0          --删除原因
    
    --调用日志服务写到文件
	skynet.send(".gametablelog", "lua", "write",tablerecords)
end

--- 向桌内的玩家广播聊天消息
-- @param tableobj
-- @param message
--
function TableLogic.sendmessage(tableobj, request,seat)
	local responmsg = {
        rid = seat.rid,
        seat_index = seat.seat_index,
        table_index = tableobj.index,
		msg_content = request.msg_content,
		chat_type = request.chat_type,
	}
	TableLogic.sendmsg_to_alltableplayer(tableobj,"playerchatN",responmsg)
end

--
--处理重新匹配(一局结束后才会重新匹配）
--
function TableLogic.restart_matchtable(tableobj)
    local rids = { }
    local curtime = timetool.get_time()
    local is_outtime = false

    --超时未准备,离线的玩家不会重新匹配
    for _, seat in pairs(tableobj.seats) do
		if not seatlogic.is_empty(seat) then
            is_outtime = false
            if curtime >= seat.ready_timeout_time or seat.is_disconnected or seat.in_tuoguan then
                is_outtime = true
            end
            if seat.state == EMJSeatState.SEAT_STATE_WAIT_START then
                table.insert(rids,seat.rid)
            end
        end
    end

    --使用call，保证先发restartmatch消息
    if tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
        skynet.call(".router","lua","coinmatch","restart_matchtable",rids,tableobj.match_type)
    else
        skynet.call(".router","lua","match","restart_matchtable",rids,tableobj.match_type)
    end

    --将匹配玩家从桌内踢出
    tableobj.has_restart_matchtable = true  --设置重新匹配标记
    for _, seat in pairs(tableobj.seats) do
        if not seatlogic.is_empty(seat) and seat.state == EMJSeatState.SEAT_STATE_WAIT_START then
            local rid,diamond = seat.rid,seat.playerinfo.diamond
            TableLogic.passive_standuptable(tableobj, {}, seat, EStandupReason.STANDUP_REASON_DELETE_TABLE)	
            TableLogic.passive_leavetable(tableobj,rid,diamond)
        end
    end
    
end

--
-- 托管
--
function TableLogic.dotuoguan(tableobj, request, seat)
	seat.is_tuoguan = request.is_tuoguan or false
    seat.in_tuoguan = seat.is_tuoguan
	local noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,	
		is_tuoguan = seat.is_tuoguan,
	}
	TableLogic.sendmsg_to_alltableplayer(tableobj,"dotuoguanN",noticemsg)

    --保存日志
    local cur_time = timetool.get_time()
    local item = "" .. cur_time .. "_" .. seat.rid .. "_" .. ((seat.is_tuoguan and "start_tuoguan") or "end_tuoguan")
    TableLogic.save_playback_record(item)

    local player_action = nil
	if seat.is_tuoguan then
		--触发托管，如果玩家当前处在操作状态执行托管操作
		if tableobj.action_player_list == nil then
			return
		end

		 player_action = tableobj.action_player_list[seat.rid]
		if player_action == nil or player_action.action_state ~= EMJActionState.NODO then
			return
		end

        if player_action.action_type ~= EMJActionType.MJ_ACTION_TYPE_CHUPAI
        and player_action.action_type ~= EMJActionType.MJ_ACTION_TYPE_GANG_CHUPAI
        and player_action.action_type ~= EMJActionType.MJ_ACTION_TYPE_SELECT then
            return
        end

		--托管操作
		gamelogic.dotuoguan(tableobj.gameobj, seat)
	else
		--取消托管计时器
		if seat.tuoguan_doaction_timerid > 0 then
			timer.cleartimer(seat.tuoguan_doaction_timerid)
			seat.tuoguan_doaction_timerid = -1
		end

        --[[
		if tableobj.action_player_list == nil then
			return
		end

		player_action = tableobj.action_player_list[seat.rid]
		if player_action == nil or player_action.action_state ~= EMJActionState.NODO then
			return
		end

        if player_action.action_type ~= EMJActionType.MJ_ACTION_TYPE_CHUPAI
        and player_action.action_type ~= EMJActionType.MJ_ACTION_TYPE_GANG_CHUPAI
        and player_action.action_type ~= EMJActionType.MJ_ACTION_TYPE_SELECT then
            return
        end

		noticemsg = {
            rid = seat.rid,
            seat_index = seat.index,
            action_timeout_time = tableobj.action_timeout_time,
            wait_action_types = tabletool.deepcopy(player_action.wait_action_types),
            card = tableobj.chu_mo_pai_card,
            remain_card_num = tableobj.cards_stack.cur_num,
        }

		--通知玩家操作
		TableLogic.sendmsg_to_tableplayer(seat.rid, "todoN", {todo_list = {noticemsg}})		
        ]]							
	end
end

--
--获取游戏名（包括桌子类型)
--
function TableLogic.get_gamename(tableobj)
    local gamename = "mjex"
    if tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
        gamename = gamename .. "_coin"
    elseif tableobj.table_type == EMJTableType.TABLE_TYPE_DIAMOND then
        gamename = gamename .. "_diamond"
    end
    return gamename
end

return TableLogic